package com.zrx.govern.component.easyexcel.starter.utils;

import com.zrx.govern.component.easyexcel.starter.ResponseExcelAutoConfiguration;
import com.zrx.govern.component.easyexcel.starter.entity.ExcelExportField;
import com.zrx.govern.component.easyexcel.starter.entity.ExcelField;
import com.zrx.govern.component.easyexcel.starter.service.EasyExcelService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.ApplicationContext;

import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author zhangxiaowei
 * @desc ExcelBean操作工具类
 */
@Slf4j
public class ExcelBeanUtil {

    /**
     * 获取当前bean
     *
     * @param model
     * @return
     */
    public static EasyExcelService getEasyExcelServiceBean(String model) {
        String beanName = JsonParseUtil.getBeanName(model);
        if (StringUtils.isBlank(beanName)) {
            throw new RuntimeException("模板json文件beanName未定义");
        }
        ApplicationContext applicationContext = ResponseExcelAutoConfiguration.getApplicationContext();
        EasyExcelService easyExcelService = (EasyExcelService) applicationContext.getBean(beanName);
        if (Objects.isNull(easyExcelService)) {
            log.info("获取导入实现bean为空,第三方未实现EasyExcelService接口");
        }
        return easyExcelService;
    }

    /**
     * 获取excel读取时的表头(即json文件定义的field字段顺序)
     *
     * @param fieldList
     * @return
     */
    public static List<List<String>> getHeads(List<ExcelField> fieldList) {
        //按照解析的json field的index排序
        fieldList.sort(Comparator.comparing(ExcelField::getIndex));
        /*按照排序后集合生成动态表头*/
        List<List<String>> headList = new ArrayList<List<String>>();
        List<String> head = null;
        for (ExcelField excelField : fieldList) {
            head = new ArrayList<>();
            head.add(excelField.getFieldName());
            headList.add(head);
        }
        return headList;
    }

    /**
     * 获取排序的Field数组
     *
     * @param clazz
     * @param fieldList
     * @return
     */
    public static Field[] getSortedFields(Class clazz, List<ExcelField> fieldList) {
        Map<String, ExcelField> fieldMap = fieldList.stream().collect(Collectors.toMap(ExcelField::getFieldEnName, Function.identity()));
        Field[] fields = clazz.getDeclaredFields();
        Field[] resultFields = new Field[fieldMap.keySet().size()];
        for (Field field : fields) {
            field.setAccessible(true);
            String fieldName = field.getName();
            if (fieldMap.containsKey(fieldName)) {
                resultFields[fieldMap.get(fieldName).getIndex()] = field;
            }
        }
        return resultFields;
    }


    /**
     * 获取排序导出的ExcelExportField对象集合
     *
     * @param clazz
     * @param fieldList
     * @return
     */
    public static List<ExcelExportField> getSortedExcelExportFields(Class clazz, List<ExcelField> fieldList) {
        List<ExcelExportField> excelExportFields = new ArrayList<>();
        Map<String, ExcelField> fieldMap = fieldList.stream().collect(Collectors.toMap(ExcelField::getFieldEnName, Function.identity()));
        Field[] fields = clazz.getDeclaredFields();
        Class superclass = clazz.getSuperclass();
        if (Objects.nonNull(superclass)) {
            /*获取父类是否有符合的字段*/
            Field[] declaredFields = superclass.getDeclaredFields();
            addExcelExportFields(excelExportFields,fieldMap,declaredFields);
        }
        addExcelExportFields(excelExportFields,fieldMap,fields);
        //ExcelExportField排序
        excelExportFields.sort(Comparator.comparing(ExcelExportField::getIndex));
        return excelExportFields;
    }

    /**
     * 获取ExcelExportField对象
     *
     * @param excelExportFields
     * @param fieldMap
     * @param fields
     */
    private static void addExcelExportFields(List<ExcelExportField> excelExportFields, Map<String, ExcelField> fieldMap, Field[] fields) {
        for (Field field : fields) {
            field.setAccessible(true);
            String fieldName = field.getName();
            if (fieldMap.containsKey(fieldName)) {
                excelExportFields.add(new ExcelExportField().setIndex(fieldMap.get(fieldName).getIndex()).setField(field)
                        .setFieldClassType(field.getType()).setFormat(fieldMap.get(fieldName).getFormat()));
            }
        }
    }

    /**
     * 获取SimpleDateFormat时间转换器
     *
     * @param excelExportFields
     * @return
     */
    public static SimpleDateFormat getSimpleDateFormat(List<ExcelExportField> excelExportFields) {
        for (ExcelExportField excelExportField : excelExportFields) {
            if (excelExportField.getFieldClassType().equals(Date.class)) {
                return new SimpleDateFormat(excelExportField.getFormat());
            }
        }
        return null;
    }

    /**
     * 获取DateTimeFormatter时间转换器
     *
     * @param excelExportFields
     * @return
     */
    public static DateTimeFormatter getDateTimeFormatter(List<ExcelExportField> excelExportFields) {
        for (ExcelExportField excelExportField : excelExportFields) {
            if (excelExportField.getFieldClassType().equals(LocalDateTime.class) || excelExportField.getFieldClassType().equals(LocalDate.class)) {
                return DateTimeFormatter.ofPattern(excelExportField.getFormat());
            }
        }
        return null;
    }

    /**
     * 获取动态fieldList
     *
     * @param clazz
     * @param fieldList
     * @return: java.util.List<com.zrx.govern.component.easyexcel.starter.entity.ExcelField>
     * @author zhangxiaowei
     **/
    public static List<ExcelField> getDynamicFiledList(Class clazz, List<ExcelField> fieldList) {
        List<ExcelField> dynamicFiledList = new ArrayList<>();
        Map<String, ExcelField> fieldMap = fieldList.stream().collect(Collectors.toMap(ExcelField::getFieldEnName, Function.identity()));
        Field[] fields = clazz.getDeclaredFields();
        Class superclass = clazz.getSuperclass();
        if (Objects.nonNull(superclass)) {
            /*获取父类是否有符合的字段*/
            Field[] declaredFields = superclass.getDeclaredFields();
            addDynamicFiledList(dynamicFiledList, fieldMap, declaredFields);
        }
        addDynamicFiledList(dynamicFiledList, fieldMap, fields);
        return dynamicFiledList;
    }

    /**
     * 获取动态fieldList
     *
     * @param dynamicFiledList
     * @param fieldMap
     * @param fields
     */
    private static void addDynamicFiledList(List<ExcelField> dynamicFiledList, Map<String, ExcelField> fieldMap, Field[] fields) {
        for (Field field : fields) {
            field.setAccessible(true);
            String fieldName = field.getName();
            if (fieldMap.containsKey(fieldName)) {
                dynamicFiledList.add(fieldMap.get(fieldName));
            }
        }
    }

    /**
     * 获取排好序导出字段
     *
     * @param clazz
     * @param fieldList
     * @return
     */
    public static List<ExcelField> getSortedDynamicFiledList(Class clazz, List<ExcelField> fieldList) {
        List<ExcelField> dynamicFiledList = getDynamicFiledList(clazz, fieldList);
        dynamicFiledList.sort(Comparator.comparing(ExcelField::getIndex));
        return dynamicFiledList;
    }

    /**
     * excel写入，根据json文件及传入的clazz生成动态表头
     *
     * @param fieldList
     * @param clazz
     * @return
     */
    public static List<List<String>> getDynamicHead(Class clazz, List<ExcelField> fieldList) {
        List<ExcelField> dynamicFiledList = getDynamicFiledList(clazz, fieldList);
        //按照解析的json field的index排序
        return getHeads(dynamicFiledList);
    }

    /**
     * 根据beanName获取业务具体实现的bean
     *
     * @param beanName
     * @return
     */
    public static Object getExecuteBean(String beanName) {
        ApplicationContext applicationContext = ResponseExcelAutoConfiguration.getApplicationContext();
        Object object = applicationContext.getBean(beanName);
        if (Objects.isNull(object)) {
            throw new RuntimeException("获取业务校验bean为空,json文件配置有误，请检查!");
        }
        return object;
    }
}
